package com.yic.module.mes.service.mo;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sun.org.apache.xpath.internal.operations.Bool;
import com.yic.framework.common.util.collection.CollectionUtils;
import com.yic.module.base.api.item.ItemApi;
import com.yic.module.base.api.item.dto.ItemRespDTO;
import com.yic.module.mes.controller.admin.modetail.vo.MoDetailCreateReqVO;
import com.yic.module.mes.controller.admin.moroute.vo.MoRouteCreateReqVO;
import com.yic.module.mes.dal.dataobject.itemproduce.ItemProduceDO;
import com.yic.module.mes.dal.dataobject.modetail.MoDetailDO;
import com.yic.module.mes.dal.dataobject.moroute.MoRouteDO;
import com.yic.module.mes.dal.dataobject.plan.PlanDO;
import com.yic.module.mes.service.itemproduce.ItemProduceService;
import com.yic.module.mes.service.modetail.MoDetailService;
import com.yic.module.mes.service.moroute.MoRouteService;
import com.yic.module.mes.service.plan.PlanService;
import com.yic.module.mes.service.report.ReportService;
import com.yic.module.system.enums.dict.MesPlanStatusEnum;
import com.yic.module.system.enums.dict.MesProduceStatusEnum;
import com.yic.module.system.enums.dict.MesSerialTypeEnum;
import com.yic.module.system.enums.dict.SystemBooleanEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.yic.module.mes.controller.admin.mo.vo.*;
import com.yic.module.mes.dal.dataobject.mo.MoDO;
import com.yic.framework.common.pojo.PageResult;

import com.yic.module.mes.convert.mo.MoConvert;
import com.yic.module.mes.dal.mysql.mo.MoMapper;

import static com.yic.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yic.module.mes.enums.ErrorCodeConstants.*;

/**
 * 生产排产 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
public class MoServiceImpl implements MoService {

    @Resource
    private MoMapper moMapper;
    @Resource
    private PlanService planService;
    @Resource
    private MoRouteService moRouteService;
    @Resource
    private MoDetailService moDetailService;
    @Resource
    private ItemApi itemApi;
    @Resource
    private ReportService reportService;
    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public void createMo(MoBatchCreateReqVO createBatchReqVO) {
        //获取排产明细
        List<MoCreateReqVO> moList = createBatchReqVO.getMoList();
        // 查询排产明细相关生产计划数据
        Set<Long> planIds = CollectionUtils.convertSet(moList, MoCreateReqVO::getPlanId);
        List<PlanDO> planList = planService.getPlanList(planIds);
        Map<Long, PlanDO> planMap = CollectionUtils.convertMap(planList, PlanDO::getId);
        // 定义排产工单集合
        List<MoDO> mos = new ArrayList<>(moList.size());
        // 定义生产计划集合
        List<PlanDO> plans = new ArrayList<>();

        moList.forEach(moCreateReqVO -> {
            //校验流水号
            if (createBatchReqVO.getSnType().equals(MesSerialTypeEnum.CUSTOM.getMesSerialType()) && StrUtil.isBlank(moCreateReqVO.getMoSns())) {
                throw exception(MO_SERIAL_NOT_EMPTY, moCreateReqVO.getCode());
            }
            // 校验生产计划（校验状态、数量）
            PlanDO plan = planMap.get(moCreateReqVO.getPlanId());
            if (ObjectUtil.isEmpty(plan)) {
                throw exception(MO_PLAN_NOT_EXISTS, moCreateReqVO.getCode());
            }
            if (MesPlanStatusEnum.ED.getMesPlanStatus().equals(plan.getStatus())) {
                throw exception(MO_NOT_PRODUCE, plan.getCode());
            }
            if (plan.getPlanAmount().subtract(plan.getProduceAmount()).compareTo(moCreateReqVO.getProduceAmount())<0) {
                throw exception(MO_PRODUCE_AMOUNT_EXCEED, moCreateReqVO.getCode());
            }else if (plan.getPlanAmount().subtract(plan.getProduceAmount()).compareTo(moCreateReqVO.getProduceAmount())>0) {
                //啥也不用干
            }else {
                plan.setStatus(MesPlanStatusEnum.ED.getMesPlanStatus());
            }
            if (!createBatchReqVO.getFactoryId().equals(moCreateReqVO.getFactoryId())){
                throw exception(MO_FACTORY_NOT_SAME);
            }
            if (!createBatchReqVO.getWorkshopId().equals(moCreateReqVO.getWorkshopId())){
                throw exception(MO_WORKSHOP_NOT_SAME);
            }
            // 组装数据
            MoDO mo = MoConvert.INSTANCE.convert(moCreateReqVO);
            mo.setWorkshopId(createBatchReqVO.getWorkshopId());
            mo.setDeptId(createBatchReqVO.getDeptId());
            mo.setMoSns(moCreateReqVO.getMoSns());
            mo.setSnType(createBatchReqVO.getSnType());
            mos.add(mo);
            plan.setProduceAmount(plan.getProduceAmount().add(moCreateReqVO.getProduceAmount()));
            plans.add(plan);
        });
        transactionTemplate.execute(status -> {
            // 插入
            moMapper.insertBatch(mos);
            // 处理工艺路线
            moRouteService.batchCreateMoRoute(mos);
            // 处理流水号
            moDetailService.batchCreateMoDetail(mos, createBatchReqVO.getSnType(), createBatchReqVO.getFactoryId());
            //变更生产计划状态
            planService.batchUpdatePlan(plans);
            return Boolean.TRUE;
        });
    }

    @Override
    public void updateMo(MoUpdateReqVO updateReqVO) {
        // 校验
        validateMoChange(updateReqVO.getId());
        // 更新
        MoDO updateObj = MoConvert.INSTANCE.convert(updateReqVO);
        List<MoDO> moList = new ArrayList<>();
        moList.add(updateObj);
        transactionTemplate.execute(status -> {
            moMapper.updateById(updateObj);
            moRouteService.deleteMoRouteByMoId(updateObj.getId());
            moRouteService.batchCreateMoRoute(moList);
            return Boolean.TRUE;
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMo(Long id) {
        // 校验
        MoDO mo = validateMoChange(id);
        // 删除
        moMapper.deleteById(id);
        // 处理生产计划
        planService.changeAmount(mo.getPlanId(), mo.getProduceAmount().negate(), null, null);
        // 删除工单工艺路线
        moRouteService.deleteMoRouteByMoId(mo.getId());
        // 删除工单详情
        moDetailService.deleteMoDetailByMoId(id);
    }

    private MoDO  validateMoChange(Long id) {
        MoDO mo = moMapper.selectById(id);
        if (ObjectUtil.isEmpty(mo)) {
            throw exception(MO_NOT_EXISTS);
        }
        // 校验是否已经开始生产
        if (!MesProduceStatusEnum.NOT.getMesProduceStatus().equals(mo.getStatus())
            || reportService.getCountByMoId(id).compareTo(BigDecimal.ZERO) > 0) {
            throw exception(MO_NOT_CHANGE);
        }
        return mo;
    }
    private MoDO validateMoExists(Long id) {
        MoDO mo = moMapper.selectById(id);
        if (mo == null) {
            throw exception(MO_NOT_EXISTS);
        }
        return mo;
    }

    @Override
    public MoDO getMo(Long id) {
        return moMapper.selectById(id);
    }

    @Override
    public List<MoDO> getMoList(Collection<Long> ids) {
        return moMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<MoDO> getMoPage(MoPageReqVO pageReqVO) {
        return moMapper.selectPage(pageReqVO);
    }

    @Override
    public List<MoDO> getMoList(MoExportReqVO exportReqVO) {
        return moMapper.selectList(exportReqVO);
    }

    @Override
    public void changeAmount(Long id, Long moRouteId, BigDecimal reportAmount, BigDecimal qualifiedAmount, BigDecimal unQualifiedAmount, BigDecimal inAmount) {
        MoDO mo = validateMoExists(id);
        if (ObjectUtil.isNotEmpty(reportAmount)) { //更新报工数量
            List<MoRouteDO> list = moRouteService.getMoRouteByMoId(id);
            if (CollectionUtil.isEmpty(list)) {
                throw exception(MO_ROUTE_NOT_EXISTS);
            }
            list.sort(Comparator.comparing(MoRouteDO::getId).reversed());
            MoRouteDO lastRoute = CollectionUtils.getFirst(list);
            // 如果为最后一道工序，需要更新生产工单数量
            if (moRouteId.equals(lastRoute.getId())) {
                mo.setReportAmount(mo.getReportAmount().add(reportAmount));
            }
            // 变更生产工单状态(通过报工总数判断)
            BigDecimal reportCount = reportService.getCountByMoId(id);
            BigDecimal temAmount = reportCount.add(reportAmount);
            BigDecimal totalProduceAmount = mo.getProduceAmount().multiply(new BigDecimal(String.valueOf(list.size())));
            if (temAmount.compareTo(totalProduceAmount) >= 0) {
                mo.setStatus(MesProduceStatusEnum.ED.getMesProduceStatus());
            }else if (temAmount.compareTo(BigDecimal.ZERO) <= 0) {
                mo.setStatus(MesProduceStatusEnum.NOT.getMesProduceStatus());
            }else {
                mo.setStatus(MesProduceStatusEnum.ING.getMesProduceStatus());
            }
            //TODO 变更生产计划
        }
        if (ObjectUtil.isNotEmpty(inAmount)) {
            BigDecimal amount = mo.getInAmount().add(inAmount);
            if (amount.compareTo(mo.getProduceAmount().subtract(mo.getInAmount())) > 0) {
                throw exception(MO_IN_GT_PRODUCE);
            }
            mo.setInAmount(amount);
        }
        // TODO 处理合格数量  不合格数量  入库数量
        moMapper.updateById(mo);
    }

    @Override
    public List<MoFormsRespVO> getMoForms(MoFormsReqVO reqVO) {
        return moMapper.getMoForms(reqVO);
    }

}
